#include <QDirIterator>
#include <QBrush>
#include <qmimedata.h>

#include "audiofile.h"
#include "playlist.h"
#include "modelplaylistentries.h"
#include "modelaudiofiles.h"

#include "debugmodule.h"

const QBrush ModelPlaylistEntries::MISSING_BRUSH = QBrush(Qt::red);
const QBrush ModelPlaylistEntries::DUPLICATE_BRUSH = QBrush(QColor("orange"));
const QBrush ModelPlaylistEntries::INCOMPLETE_BRUSH = QBrush(Qt::magenta);
QIcon ModelPlaylistEntries::DEFAULT_ICON = QIcon();

ModelPlaylistEntries::ModelPlaylistEntries(QObject *parent) :
    QAbstractTableModel(parent), m_pPlaylist(NULL), m_pEntries(NULL)
{
    // Icon erstellen (geht nicht statisch)
    if (DEFAULT_ICON.isNull())
        DEFAULT_ICON = QIcon(":/icons/audioFile");
}

int ModelPlaylistEntries::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid() || m_pEntries == NULL)
        return 0;
    else
        return m_pEntries->size();
}

int ModelPlaylistEntries::columnCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    else
        return MaxColIdx;
}

QVariant ModelPlaylistEntries::data(const QModelIndex &index, int role) const
{
    if (m_pEntries)
    {
        switch (role)
        {
        case Qt::DisplayRole:
        case Qt::EditRole:
            switch(index.column())
            {
            case State:
            {
                const PlaylistEntry* entry = m_pEntries->at(index.row());
                if (entry->isMissing())
                    return QStringLiteral("Fehlt");
                else if (entry->isDuplicate())
                    return QStringLiteral("Duplikat");
                else if (!entry->isCompleteAndValid())
                    return "Unvollständig";
                else
                    return QStringLiteral("OK");
            }
            case Filename:
                return m_pEntries->at(index.row())->filename();
            case Title:
                return m_pEntries->at(index.row())->title();
            case Artist:
                return m_pEntries->at(index.row())->artist();
            case Album:
                return m_pEntries->at(index.row())->album();
            case Genre:
                return m_pEntries->at(index.row())->genre();
            case Track:
                return m_pEntries->at(index.row())->track();
            case Year:
                return m_pEntries->at(index.row())->year();
            }
            break;

        case Qt::ToolTipRole:
            if (index.column() == Filename)
                return m_pEntries->at(index.row())->filepath();
            break;

        case Qt::TextAlignmentRole:
        {
            Qt::Alignment alignment = Qt::AlignVCenter;
            alignment |= index.column() < Track ?
                        Qt::AlignLeft : Qt::AlignRight;
            return QVariant(alignment);
        }

        case Qt::DecorationRole:
            if (index.column() == 0)
            {
                const AudioFile* pAudioFile = m_pEntries->at(index.row())->audioFile();
                return pAudioFile ? pAudioFile->cover() : DEFAULT_ICON;
            }
            break;

        case Qt::BackgroundRole:
            const PlaylistEntry* entry = m_pEntries->at(index.row());
            if (entry->isMissing())
                return MISSING_BRUSH;
            else if (entry->isDuplicate())
                return DUPLICATE_BRUSH;
            else if (!entry->isCompleteAndValid())
                return INCOMPLETE_BRUSH;
            break;
        }
    }

    return QVariant();
}

bool ModelPlaylistEntries::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if (index.isValid() && m_pEntries && role == Qt::EditRole &&
            value.type() == QVariant::String)
    {
        switch(index.column())
        {
        case Title:
            m_pEntries->at(index.row())->setTitle(value.toString());
            break;
        case Artist:
            m_pEntries->at(index.row())->setArtist(value.toString());
            break;
        case Album:
            m_pEntries->at(index.row())->setAlbum(value.toString());
            break;
        case Genre:
            m_pEntries->at(index.row())->setGenre(value.toString());
            break;
        case Track:
            m_pEntries->at(index.row())->setTrack(value.toString());
            break;
        case Year:
            m_pEntries->at(index.row())->setYear(value.toString());
            break;
        default:
            return false;
        }
        return true;
    }

    return false;
}

QVariant ModelPlaylistEntries::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
    {
        switch(section)
        {
        case State:
            return QStringLiteral("Status");
        case Filename:
            return QStringLiteral("Dateiname");
        case Title:
            return QStringLiteral("Titel");
        case Artist:
            return QStringLiteral("Interpret");
        case Album:
            return QStringLiteral("Album");
        case Genre:
            return QStringLiteral("Genre");
        case Track:
            return QStringLiteral("Track");
        case Year:
            return QStringLiteral("Jahr");
        }
    }

    return QVariant();
}

Qt::ItemFlags ModelPlaylistEntries::flags(const QModelIndex &index) const
{
    const Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);

    if (!index.isValid() && m_pEntries)
        return defaultFlags | Qt::ItemIsDropEnabled;
    else if (index.isValid() && m_pEntries && index.column() > Filename)
        return defaultFlags | Qt::ItemIsEditable;
    else
        return defaultFlags;
}

QStringList ModelPlaylistEntries::mimeTypes() const
{
    static QStringList l(ModelAudioFiles::MIME_TYPE);
    return l;
}

bool ModelPlaylistEntries::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
    Q_UNUSED(row);
    Q_UNUSED(column);

    if (m_pPlaylist == NULL || parent.isValid() ||
            !data->hasFormat(ModelAudioFiles::MIME_TYPE))
    {
        return false;
    }
    else if (action == Qt::CopyAction)
    {
        // Dateien einfügen
        QByteArray encodedData = data->data(ModelAudioFiles::MIME_TYPE);
        QDataStream stream(&encodedData, QIODevice::ReadOnly);
        QList<AudioFile*> files;
        int filePointer = 0;

        while(!stream.atEnd())
        {
            stream >> filePointer;
            files << reinterpret_cast<AudioFile*>(filePointer);
        }

        beginResetModel();
        m_pPlaylist->addAudioFiles(files);
        endResetModel();

        emit countChanged(rowCount());
        return true;
    }

    return false;
}

void ModelPlaylistEntries::show(Playlist* i_pPlaylist)
{
    // Disconnect
    if (m_pEntries)
    {
        for (int i = 0; i < m_pEntries->size(); i++)
            disconnect(m_pEntries->at(i), 0, this, 0);
    }

    beginResetModel();
    m_pPlaylist = i_pPlaylist;
    m_pEntries = i_pPlaylist ? &i_pPlaylist->entries() : NULL;
    endResetModel();

    // Connect
    if (m_pEntries)
    {
        for (int i = 0; i < m_pEntries->size(); i++)
            connect(m_pEntries->at(i), SIGNAL(dataChanged()), SLOT(entryChanged()));
    }

    emit countChanged(rowCount());
}

void ModelPlaylistEntries::remove(int i_idx)
{
    if (m_pPlaylist)
    {
        beginRemoveRows(QModelIndex(), i_idx, i_idx);

        // Auch aus Playliste löschen
        m_pPlaylist->removeEntry(i_idx);
        m_pEntries = &m_pPlaylist->entries();

        endRemoveRows();

        emit countChanged(rowCount());
    }
}

void ModelPlaylistEntries::entryChanged()
{
    if (m_pEntries == NULL)
        return;

    if (PlaylistEntry* pEntry = qobject_cast<PlaylistEntry*>(sender()))
    {
        const int idx = m_pEntries->indexOf(pEntry);

        if (idx > -1)
        {
            emit dataChanged(index(idx,0), index(idx,MaxColIdx - 1));
        }
    }
}
